package lex.mtd.ui.utils;

import java.awt.Color;
import java.awt.Component;
import java.awt.Rectangle;
import java.io.Serializable;

import javax.swing.*;
import javax.swing.border.Border;
import javax.swing.border.EmptyBorder;
import javax.swing.table.TableCellRenderer;

import lex.mtd.utils.PercentFormatter;

public class PercentRenderer extends JProgressBar implements TableCellRenderer, Serializable
{
	private static final Border SAFE_NO_FOCUS_BORDER = new EmptyBorder( 1, 1, 1, 1 );
	private Color unselectedBackground;

	/**
	 * Creates a default table cell renderer.
	 */
	public PercentRenderer()
	{
		super();
		setOpaque( true );
		setBorder( SAFE_NO_FOCUS_BORDER );
		this.setBorderPainted( false );
		this.setStringPainted( true );
	}

	/**
	 * Overrides <code>JComponent.setBackground</code> to assign the
	 * unselected-background color to the specified color.
	 * 
	 * @param c
	 *        set the background color to this value
	 */
	@Override
	public void setBackground( Color c )
	{
		super.setBackground( c );
		unselectedBackground = c;
	}

	/**
	 * Notification from the <code>UIManager</code> that the look and feel [L&F]
	 * has changed. Replaces the current UI object with the latest version from
	 * the <code>UIManager</code>.
	 * 
	 * @see JComponent#updateUI
	 */
	@Override
	public void updateUI()
	{
		super.updateUI();
		setBackground( null );
	}

	// implements javax.swing.table.TableCellRenderer
	/**
	 * Returns the default table cell renderer.
	 * <p>
	 * During a printing operation, this method will be called with
	 * <code>isSelected</code> and <code>hasFocus</code> values of
	 * <code>false</code> to prevent selection and focus from appearing in the
	 * printed output. To do other customization based on whether or not the
	 * table is being printed, check the return value from
	 * {@link javax.swing.JComponent#isPaintingForPrint()}.
	 * 
	 * @param table
	 *        the <code>JTable</code>
	 * @param value
	 *        the value to assign to the cell at <code>[row, column]</code>
	 * @param isSelected
	 *        true if cell is selected
	 * @param hasFocus
	 *        true if cell has focus
	 * @param row
	 *        the row of the cell to render
	 * @param column
	 *        the column of the cell to render
	 * @return the default table cell renderer
	 * @see javax.swing.JComponent#isPaintingForPrint()
	 */
	public Component getTableCellRendererComponent( JTable table, Object value, boolean isSelected,
		boolean hasFocus, int row, int column )
	{
		Color bg = null;
		JTable.DropLocation dropLocation = table.getDropLocation();
		if( dropLocation != null && !dropLocation.isInsertRow() && !dropLocation.isInsertColumn()
				&& dropLocation.getRow() == row && dropLocation.getColumn() == column )
		{
			bg = UIManager.getColor( "Table.dropCellBackground" );
			isSelected = true;
		}
		if( isSelected )
		{
			super.setBackground( bg == null ? table.getSelectionBackground() : bg );
		}
		else
		{
			super.setBackground( unselectedBackground != null ? unselectedBackground : table
				.getBackground() );
		}
		setFont( table.getFont() );
		if( hasFocus )
		{
			Border border = null;
			if( isSelected )
			{
				border = UIManager.getBorder( "Table.focusSelectedCellHighlightBorder" );
			}
			if( border == null )
			{
				border = UIManager.getBorder( "Table.focusCellHighlightBorder" );
			}
			setBorder( border );
			if( !isSelected && table.isCellEditable( row, column ) )
			{
				Color col = UIManager.getColor( "Table.focusCellBackground" );
				if( col != null )
				{
					super.setBackground( col );
				}
			}
		}
		else
		{
			setBorder( SAFE_NO_FOCUS_BORDER );
		}
		setValue( value );
		return this;
	}

	/**
	 * Sets the <code>String</code> object for the cell being rendered to
	 * <code>value</code>.
	 * 
	 * @param value
	 *        the string value for this cell; if value is <code>null</code> it
	 *        sets the text value to an empty string
	 * @see JLabel#setText
	 */
	protected void setValue( Object value )
	{
		int n = 0;
		String text = "";
		if( value instanceof Number )
		{
			double p = ((Number) value).doubleValue();
			n = (int) Math.round( 100 * p );
			text = PercentFormatter.format( p );
		}
		this.setValue( n );
		this.setString( text );
	}

	/*
	 * The following methods are overridden as a performance measure to to prune
	 * code-paths are often called in the case of renders but which we know are
	 * unnecessary. Great care should be taken when writing your own renderer to
	 * weigh the benefits and drawbacks of overriding methods like these.
	 */
	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	public boolean isOpaque()
	{
		Color back = getBackground();
		Component p = getParent();
		if( p != null )
		{
			p = p.getParent();
		}
		// p should now be the JTable.
		boolean colorMatch = (back != null) && (p != null) && back.equals( p.getBackground() )
				&& p.isOpaque();
		return !colorMatch && super.isOpaque();
	}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 * 
	 * @since 1.5
	 */
	@Override
	public void invalidate()
	{}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	public void validate()
	{}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	public void revalidate()
	{}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	public void repaint( long tm, int x, int y, int width, int height )
	{}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	public void repaint( Rectangle r )
	{}

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 * 
	 * @since 1.5
	 */
	@Override
	public void repaint()
	{}

	static final String[] PROPERTY_NAME = { "orientation", "stringPainted", "string",
			"borderPainted", "indeterminate" };

	/**
	 * Overridden for performance reasons. See the <a
	 * href="#override">Implementation Note</a> for more information.
	 */
	@Override
	protected void firePropertyChange( String propertyName, Object oldValue, Object newValue )
	{
		// Strings get interned...
		if( -1 != org.lex.utils.Arrays.firstEquals( PROPERTY_NAME, propertyName )
				&& oldValue != newValue )
		{
			super.firePropertyChange( propertyName, oldValue, newValue );
		}
	}
}
